from typing import Set
from Cut import Cut
from GetStopWords import GetStopWrods
import os
import random
import pandas as pd

def sampleNFold(totalNumber, N = 5):
    container = [i for i in range(totalNumber)]
    numberPerFold = int(totalNumber / N)
    sampledContainer = []
    for i in range(N):
        c = random.sample(container, numberPerFold)
        sampledContainer.append(c)
        for item in c:
            container.remove(item)
    return sampledContainer

class SetProbability():

    def __init__(self, N = 5):
        self.N = N
        self.sampledContainer = sampleNFold(997, self.N)
        self.defaults = {}
        self.classPaths = []
        self.wordsContainer = []
        self.wordsDictionary = {}
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        data = [[0 for i in range(len(CLASSES_LIST))] for j in range(len(CLASSES_LIST))]
        self.confusionMatrix = pd.DataFrame(data, index = CLASSES_LIST, columns = CLASSES_LIST) 
        for dir in CLASSES_LIST:
            classPath = CLASSES_PATH + dir + "/"
            self.classPaths.append(classPath)
            files = os.listdir(classPath)
            self.__dict__[dir + "files"] = files
            # print(len(files))
            self.defaults[dir + "WordMatrix"] = []
            self.defaults[dir + "BoolMatrix"] = []
            self.defaults[dir + "WordContainer"] = []
            self.defaults[dir + "WordDictionary"] = {}
        self.__dict__.update(self.defaults)

    def clearLastFold(self):
        self.defaults = {}
        # self.classPaths = []
        self.wordsContainer = []
        self.wordsDictionary = {}
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        data = [[0 for i in range(len(CLASSES_LIST))] for j in range(len(CLASSES_LIST))]
        self.confusionMatrix = pd.DataFrame(data, index = CLASSES_LIST, columns = CLASSES_LIST) 
        for dir in CLASSES_LIST:
            self.defaults[dir + "WordMatrix"] = []
            self.defaults[dir + "BoolMatrix"] = []
            self.defaults[dir + "WordContainer"] = []
            self.defaults[dir + "WordDictionary"] = {}
        self.__dict__.update(self.defaults)


    def setWordsContainer(self, kth):

        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        
        self.clearLastFold()

        for dir in CLASSES_LIST:
            # print(CLASSES_PATH + dir + "/")
            classPath = CLASSES_PATH + dir + "/"
            # self.classPaths.append(classPath)
            files = self.__dict__[dir + "files"]
            flagOfNumber = 0
            for file in files:
                if flagOfNumber in self.sampledContainer[kth]:
                    flagOfNumber += 1
                    continue
                flagOfNumber += 1
                filepath = classPath + file
                stopWordsPath = "stopwords.txt"
                g = GetStopWrods()
                stopWords = g.Call(stopWordsPath)
                c = Cut(stopWords)
                wordsList = c.Call(filepath)
                self.__dict__[dir + "WordMatrix"].append(wordsList)
                self.__dict__[dir + "WordContainer"].extend(wordsList)
                self.__dict__[dir + "WordContainer"] = list(set(self.__dict__[dir + "WordContainer"]))
                self.wordsContainer.extend(wordsList)
                self.wordsContainer = list(set(self.wordsContainer))
        print(str(len(self.wordsContainer)) + "\n")

    def setWordsDictionary(self):
        print("WordsDictionary Set begin." + "\n")
        for i in range(len(self.wordsContainer)):
            self.wordsDictionary[self.wordsContainer[i]] = i
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        for dir in CLASSES_LIST:
            for i in range(len(self.__dict__[dir + "WordContainer"])):
                self.__dict__[dir + "WordDictionary"][self.__dict__[dir + "WordContainer"][i]] = i
        print("WordsDictionary Set end." + "\n")
    
    def setBoolMatrix(self):
        print("BoolMatrix Set begin." + "\n")
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        for dir in CLASSES_LIST:
            # print("dir \n")
            for list in self.__dict__[dir + "WordMatrix"]:
                tmpList = [0 for i in range(len(self.__dict__[dir + "WordContainer"]))]
                for i in range(len(list)):
                    if tmpList[self.__dict__[dir + "WordDictionary"][list[i]]] == 0:
                        tmpList[self.__dict__[dir + "WordDictionary"][list[i]]] = 1
                self.__dict__[dir + "BoolMatrix"].append(tmpList)
        print("BoolMatrix Set end." + "\n")

    def setConditionalProbability(self):
        print("ConditionalProbability Set begin." + "\n")
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        for dir in CLASSES_LIST:
            # print("dir \n")
            SUM = len(self.__dict__[dir + "WordContainer"])
            self.__dict__[dir + "CP"] = [1.0 for i in range(len(self.__dict__[dir + "WordContainer"]))]
            for list in range(len(self.__dict__[dir + "BoolMatrix"])):
                for i in range(len(self.__dict__[dir + "WordContainer"])):
                    self.__dict__[dir + "CP"][i] = self.__dict__[dir + "CP"][i] + self.__dict__[dir + "BoolMatrix"][list][i]
                    SUM = SUM + self.__dict__[dir + "BoolMatrix"][list][i]
            self.__dict__[dir + "SUM"] = SUM
            for i in range(len(self.__dict__[dir + "WordContainer"])):
                self.__dict__[dir + "CP"][i] = self.__dict__[dir + "CP"][i] / SUM
        print("ConditionalProbability Set end." + "\n")
    
    def train(self):
        for i in range(self.N):
            self.setWordsContainer(i)
            self.setWordsDictionary()
            self.setBoolMatrix()
            self.setConditionalProbability()
            self.verify(i)
            predClass, predProbability = self.predict("52558")
            print(predClass)

    def predict(self, filepath):
        print("Predict begin." + "\n")
        stopWordsPath = "stopwords.txt"
        g = GetStopWrods()
        stopWords = g.Call(stopWordsPath)
        c = Cut(stopWords)
        wordsList = c.Call(filepath)
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        maxProbability = 0.0
        maxClass = None
        for dir in CLASSES_LIST:
            tmpProbability = 1.0
            for i in range(len(wordsList)):
                if wordsList[i] in self.__dict__[dir + "WordDictionary"]:
                    tmpProbability = tmpProbability * self.__dict__[dir + "CP"][self.__dict__[dir + "WordDictionary"][wordsList[i]]]
                else:
                    tmpProbability = tmpProbability / (self.__dict__[dir + "SUM"] + 1)
            if tmpProbability > maxProbability:
                maxProbability = tmpProbability
                maxClass = dir
        print("Predict end." + "\n")
        return maxClass, maxProbability

    def verify(self, kth):
        print("Verify begin." + "\n")
        T = 0
        F = 0
        stopWordsPath = "stopwords.txt"
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        for dir in CLASSES_LIST:
            classPath = CLASSES_PATH + dir + "/"
            for item in self.sampledContainer[kth]:
                filepath = classPath + self.__dict__[dir + "files"][item]
                g = GetStopWrods()
                stopWords = g.Call(stopWordsPath)
                c = Cut(stopWords)
                wordsList = c.Call(filepath)

                maxProbability = 0.0
                maxClass = None
                minUnseen = 10000000
                for dir2 in CLASSES_LIST:
                    tmpProbability = 1.0
                    unseen = 0
                    for i in range(len(wordsList)):
                        if wordsList[i] in self.__dict__[dir2 + "WordDictionary"]:
                            tmpProbability = tmpProbability * self.__dict__[dir2 + "CP"][self.__dict__[dir2 + "WordDictionary"][wordsList[i]]]
                        else:
                            unseen += 1
                            tmpProbability = tmpProbability / (self.__dict__[dir2 + "SUM"] + 1)
                    if tmpProbability > maxProbability:
                        maxProbability = tmpProbability
                        maxClass = dir2
                    if maxProbability == 0:
                        if unseen < minUnseen:
                            maxClass = dir2
                            minUnseen = unseen
                if maxClass == dir:
                    T += 1
                else:
                    F += 1
                self.confusionMatrix.at[dir, maxClass] += 1
        print("Cross Verify {}: Precisely predicted: {}, Mistakely predicted: {}".format(kth, T, F))
        print(self.confusionMatrix)
        print("Verify end." + "\n")

s = SetProbability()
s.train()
predClass, predProbability = s.predict("52558")
print(predClass)